<!DOCTYPE html>
<html lang="zh-CN" data-theme="light">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>硅基 KEY 池 - 密钥管理</title>
    <link rel="icon" type="image/x-icon" href="/static/logo.png">
    <!-- 预加载字体 -->
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <style type="text/css">
        /* 使用系统字体回退，减少外部字体依赖 */
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
        }
        /* 只保留必要的字体，设置font-display为swap确保文本可见 */
        @font-face {
            font-family: 'Inter';
            font-style: normal;
            font-weight: 400;
            src: local('Inter Regular'), local('Inter-Regular'), 
                 url(/cf-fonts/v/inter/5.0.16/latin/wght/normal.woff2) format('woff2');
            font-display: swap;
        }
        @font-face {
            font-family: 'Inter';
            font-style: normal;
            font-weight: 600;
            src: local('Inter SemiBold'), local('Inter-SemiBold'), 
                 url(/cf-fonts/v/inter/5.0.16/latin/wght/normal.woff2) format('woff2');
            font-display: swap;
        }
    </style>
    <style>
        :root {
            --primary: #6B46C1;
            --primary-hover: #553C9A;
            --secondary: #64748B;
            --success: #10B981;
            --danger: #EF4444;
            --warning: #F59E0B;
            --bg-light: #F8FAFC;
            --bg-white: #FFFFFF;
            --text-dark: #1F2937;
            --text-muted: #64748B;
            --border: #E2E8F0;
            --shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
            --card-border: #E2E8F0;
            --progress-bg: #E2E8F0;
            --status-active-bg: rgba(16, 185, 129, 0.1);
            --status-expired-bg: rgba(239, 68, 68, 0.1);
            --progress-fill-success: #10B981;
            --progress-fill-warning: #F59E0B;
            --progress-fill-danger: #EF4444;
        }

        /* Dark theme variables */
        [data-theme="dark"] {
            --primary: #8B5CF6;
            --primary-hover: #7C3AED;
            --secondary: #94A3B8;
            --success: #10B981;
            --danger: #EF4444;
            --warning: #F59E0B;
            --bg-light: #1E293B;
            --bg-white: #0F172A;
            --text-dark: #F1F5F9;
            --text-muted: #94A3B8;
            --border: #334155;
            --shadow: 0 2px 10px rgba(0, 0, 0, 0.25);
            --card-border: #334155;
            --progress-bg: #334155;
            --status-active-bg: rgba(16, 185, 129, 0.2);
            --status-expired-bg: rgba(239, 68, 68, 0.2);
            --progress-fill-success: #10B981;
            --progress-fill-warning: #F59E0B;
            --progress-fill-danger: #EF4444;
        }

        * { box-sizing: border-box; margin: 0; padding: 0; }
        body { font-family: 'Inter', sans-serif; background: var(--bg-light); color: var(--text-dark); line-height: 1.6; min-height: 100vh; }
        .container { max-width: 1280px; margin: 0 auto; padding: 0 1rem; }
        .card { background: var(--bg-white); border-radius: 0.75rem; box-shadow: var(--shadow); padding: 1.5rem; margin-bottom: 1.5rem; border: 1px solid var(--card-border); }
        
        /* Modern UI elements */
        .header { background: var(--bg-white); padding: 1rem 0; border-bottom: 1px solid var(--border); }
        .header-content { display: flex; justify-content: space-between; align-items: center; }
        .header-title { display: flex; align-items: center; gap: 0.75rem; }
        .logo { width: 2rem; height: 2rem; }
        .app-title { font-size: 1.25rem; font-weight: 600; color: var(--primary); }
        
        .nav-actions { display: flex; align-items: center; gap: 1rem; }
        .theme-toggle { background: transparent; border: none; cursor: pointer; color: var(--text-muted); }
        .nav-links { display: flex; gap: 0.5rem; background: var(--bg-light); padding: 0.25rem; border-radius: 0.5rem; }
        .nav-link { color: var(--text-muted); text-decoration: none; padding: 0.5rem 1rem; border-radius: 0.375rem; transition: all 0.2s; }
        .nav-link:hover, .logout-btn:hover { background: rgba(107, 70, 193, 0.1); color: var(--primary); }
        .nav-link.active { color: var(--primary); background: rgba(107, 70, 193, 0.1); font-weight: 500; }
        .logout-btn { color: var(--danger); text-decoration: none; padding: 0.5rem 1rem; border-radius: 0.375rem; transition: all 0.2s; }
        
        .main-content { padding: 2rem 0; }
        .section { margin-bottom: 2rem; }
        .section-title { font-size: 1.25rem; font-weight: 600; margin-bottom: 1rem; display: flex; align-items: center; gap: 0.5rem; }
        
        .button-group { display: flex; gap: 0.75rem; margin-bottom: 1.5rem; }
        button, .btn-primary, .btn-secondary, .btn-danger { 
            display: flex; align-items: center; gap: 0.5rem; font-weight: 500; padding: 0.625rem 1.25rem; 
            border-radius: 0.5rem; border: none; cursor: pointer; transition: all 0.2s;
        }
        .btn-primary { background: var(--primary); color: white; }
        .btn-primary:hover { background: var(--primary-hover); }
        .btn-secondary { background: var(--bg-white); color: var(--primary); border: 1px solid var(--border); }
        .btn-secondary:hover { border-color: var(--primary); background: rgba(107, 70, 193, 0.05); }
        .btn-danger { background: var(--bg-white); color: var(--danger); border: 1px solid var(--border); }
        .btn-danger:hover { border-color: var(--danger); background: rgba(239, 68, 68, 0.05); }
        
        /* Stats grid */
        .stats-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; margin-bottom: 1.5rem; }
        .stat-card { background: var(--bg-white); padding: 1.25rem; border-radius: 0.75rem; box-shadow: var(--shadow); 
                    border: 1px solid var(--border); display: flex; align-items: center; gap: 1rem; }
        .stat-icon { width: 3rem; height: 3rem; display: flex; align-items: center; justify-content: center; 
                    border-radius: 0.75rem; flex-shrink: 0; }
        .stat-icon-users { background: rgba(147, 51, 234, 0.15); color: #9333ea; }
        .stat-icon-active { background: rgba(22, 163, 74, 0.15); color: #16a34a; }
        .stat-icon-calls { background: rgba(234, 88, 12, 0.15); color: #ea580c; }
        .stat-icon-tokens { background: rgba(2, 132, 199, 0.15); color: #0284c7; }
        .stat-content { display: flex; flex-direction: column; }
        .stat-label { color: var(--text-muted); font-size: 0.875rem; }
        .stat-value { font-weight: 700; font-size: 1.5rem; line-height: 1.2; }
        
        /* Search and filters */
        .filter-container { display: flex; flex-wrap: wrap; gap: 1rem; margin-bottom: 1.5rem; 
                         background: var(--bg-white); padding: 1rem; border-radius: 0.75rem; 
                         border: 1px solid var(--border); box-shadow: var(--shadow); }
        .filter-group { display: flex; align-items: center; gap: 0.5rem; }
        .filter-label { color: var(--text-muted); font-size: 0.875rem; white-space: nowrap; }
        .filter-input { padding: 0.5rem; background: var(--bg-light); color: var(--text-dark); 
                      border: 1px solid var(--border); border-radius: 0.375rem; font-size: 0.875rem; }
        .filter-input:focus { outline: none; border-color: var(--primary); }
        
        /* Table styles */
        .table-container { overflow-x: auto; background: var(--bg-white); border-radius: 0.75rem; 
                         box-shadow: var(--shadow); border: 1px solid var(--border); margin-bottom: 1.5rem; }
        table { width: 100%; border-collapse: collapse; }
        th, td { padding: 1rem; text-align: left; border-bottom: 1px solid var(--border); font-size: 0.875rem; }
        th { font-weight: 600; background: rgba(107, 70, 193, 0.05); position: relative; }
        tr:last-child td { border-bottom: none; }
        tr:hover td { background: rgba(107, 70, 193, 0.02); }
        
        /* Messages */
        #message { padding: 1rem; border-radius: 0.5rem; margin-bottom: 1.5rem; display: none; font-size: 0.875rem; }
        .success { background: var(--status-active-bg); color: var(--success); border: 1px solid rgba(16, 185, 129, 0.2); display: block !important; }
        .error { background: var(--status-expired-bg); color: var(--danger); border: 1px solid rgba(239, 68, 68, 0.2); display: block !important; }
        
        /* Pagination */
        .pagination-container { display: flex; align-items: center; justify-content: space-between; margin-bottom: 1.5rem; }
        .pagination { display: flex; gap: 0.5rem; }
        .pagination button { min-width: 5rem; }
        .pagination button:disabled { opacity: 0.5; cursor: not-allowed; }
        
        /* Responsive */
        @media (max-width: 992px) {
            .stats-grid { grid-template-columns: repeat(2, 1fr); }
        }
        @media (max-width: 768px) {
            .header-content { flex-direction: column; align-items: flex-start; gap: 1rem; }
            .nav-links { width: 100%; justify-content: space-around; }
            .stats-grid { grid-template-columns: repeat(2, 1fr); gap: 0.75rem; }
            .filter-container { flex-direction: column; align-items: stretch; }
            .button-group { flex-wrap: wrap; }
            .button-group button { flex: 1 1 calc(50% - 0.5rem); }
            .hide-on-mobile { display: none; }
        }
        @media (max-width: 576px) {
            .stats-grid { grid-template-columns: 1fr; }
            .button-group button { flex: 1 1 100%; }
        }
        
        /* Custom elements */
        .key-display { display: flex; align-items: center; gap: 0.5rem; }
        .masked-key, .full-key { cursor: pointer; font-family: monospace; }
        .copy-btn { background: transparent; border: none; color: var(--text-muted); cursor: pointer; padding: 0.25rem; border-radius: 0.25rem; }
        .copy-btn:hover { background: rgba(107, 70, 193, 0.1); color: var(--primary); }
        .key-actions { display: flex; gap: 0.5rem; }
        .action-btn { font-size: 0.75rem; padding: 0.25rem 0.5rem; border-radius: 0.25rem; }
        .refresh-btn { background: rgba(107, 70, 193, 0.1); color: var(--primary); border: none; }
        .refresh-btn:hover { background: rgba(107, 70, 193, 0.2); }
    </style>
</head>

<body>
    <header class="header">
        <div class="container">
            <div class="header-content">
                <div class="header-title">
                    <img src="/static/logo.png" alt="Logo" class="logo">
                    <h1 class="app-title">硅基 KEY 池 - 密钥管理</h1>
                </div>
                <div class="nav-actions">
                    <button id="themeToggle" class="theme-toggle" title="切换主题">
                        <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                            <path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"></path>
                        </svg>
                    </button>
                    <div class="nav-links">
                        <a href="/admin" class="nav-link">首页</a>
                        <a href="/keys" class="nav-link active">密钥管理</a>
                        <a href="/stats" class="nav-link">使用统计</a>
                        <a href="/logout" class="logout-btn">退出</a>
                    </div>
                </div>
            </div>
        </div>
    </header>

    <main class="main-content">
        <div class="container">
            <section class="section">
                <div class="button-group">
                    <button class="btn-primary" onclick="refreshAllKeys()">
                        <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                            <path d="M21.5 2v6h-6M2.5 22v-6h6M2 11.5a10 10 0 0 1 18.8-4.3M22 12.5a10 10 0 0 1-18.8 4.2"></path>
                        </svg>
                        刷新所有密钥
                    </button>
                    <button class="btn-secondary" onclick="location.href='/admin'">
                        <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                            <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
                            <polyline points="17 8 12 3 7 8"></polyline>
                            <line x1="12" y1="3" x2="12" y2="15"></line>
                        </svg>
                        导入新密钥
                    </button>
                </div>
            </section>

            <div id="message"></div>

            <section class="section">
                <div class="stats-grid">
                    <div class="stat-card">
                        <div class="stat-icon stat-icon-users">
                            <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                                <path d="M16 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path>
                                <circle cx="8.5" cy="7" r="4"></circle>
                                <path d="M20 8h2a4 4 0 0 1-4 4h-3.1"></path>
                                <path d="M15 21H3a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h12a2 2 0 0 1 2 2v16a2 2 0 0 1-2 2z"></path>
                            </svg>
                        </div>
                        <div class="stat-content">
                            <div class="stat-label">总密钥数量</div>
                            <div class="stat-value" id="totalKeysCount">0</div>
                        </div>
                    </div>
                    <div class="stat-card">
                        <div class="stat-icon stat-icon-active">
                            <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                                <path d="M12 22C6.48 22 2 17.52 2 12S6.48 2 12 2s10 4.48 10 10-4.48 10-10 10z"></path>
                                <path d="M12 16c-2.21 0-4-1.79-4-4s1.79-4 4-4 4 1.79 4 4-1.79 4-4 4z"></path>
                            </svg>
                        </div>
                        <div class="stat-content">
                            <div class="stat-label">总余额</div>
                            <div class="stat-value" id="totalBalance">¥0.00</div>
                        </div>
                    </div>
                    <div class="stat-card">
                        <div class="stat-icon stat-icon-calls">
                            <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                                <path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-2.08 19.58 19.58 0 0 1-6-2 2 2 0 0 1-2-2v-3a2 2 0 0 1 2.18-2 19.79 19.79 0 0 1 8.63 2.08 19.58 19.58 0 0 1 6 2 2 2 0 0 1 2 2z"></path>
                                <path d="M22 10.24A2 2 0 0 1 20.18 8 19.79 19.79 0 0 1 12 6C5.21 4.92 2 8.14 2 12c0 3.86 3.21 7.08 10 8.14"></path>
                            </svg>
                        </div>
                        <div class="stat-content">
                            <div class="stat-label">总调用次数</div>
                            <div class="stat-value" id="totalCallCount">0</div>
                        </div>
                    </div>
                    <div class="stat-card">
                        <div class="stat-icon stat-icon-tokens">
                            <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                                <path d="M21 12.79A2 2 0 0 0 19 15v2a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-2.08 19.58 19.58 0 0 1-6-2 2 2 0 0 1-2-2v-3a2 2 0 0 1 2.18-2 19.79 19.79 0 0 1 8.63 2.08 19.58 19.58 0 0 1 6 2 2 2 0 0 1 2 2z"></path>
                                <path d="M12 16c-2.21 0-4-1.79-4-4s1.79-4 4-4 4 1.79 4 4-1.79 4-4 4z"></path>
                            </svg>
                        </div>
                        <div class="stat-content">
                            <div class="stat-label">总tokens消耗</div>
                            <div class="stat-value" id="totalTokens">0</div>
                        </div>
                    </div>
                </div>
            </section>

            <section class="section">
                <div class="filter-container">
                    <div class="filter-group">
                        <span class="filter-label">密钥搜索:</span>
                        <input type="text" id="keyFilter" class="filter-input" placeholder="输入密钥关键字" onkeyup="applyFilters()">
                    </div>
                    <div class="filter-group">
                        <span class="filter-label">排序字段:</span>
                        <select id="sortField" class="filter-input" onchange="changeSorting()">
                            <option value="add_time">添加时间</option>
                            <option value="balance">余额</option>
                            <option value="usage_count">使用次数</option>
                        </select>
                    </div>
                    <div class="filter-group">
                        <span class="filter-label">排序方式:</span>
                        <select id="sortOrder" class="filter-input" onchange="changeSorting()">
                            <option value="desc">降序</option>
                            <option value="asc">升序</option>
                        </select>
                    </div>
                </div>
            </section>

            <section class="section">
                <div class="table-container">
                    <table id="keysTable">
                        <thead>
                            <tr>
                                <th onclick="sortKeys('key')">密钥</th>
                                <th onclick="sortKeys('balance')">余额</th>
                                <th onclick="sortKeys('usage_count')">使用次数</th>
                                <th class="hide-on-mobile" onclick="sortKeys('add_time')">添加时间</th>
                                <th>操作</th>
                            </tr>
                        </thead>
                        <tbody>
                            <tr>
                                <td colspan="5" style="text-align: center;">加载中...</td>
                            </tr>
                        </tbody>
                    </table>
                </div>

                <div class="pagination-container">
                    <div class="pagination-info">
                        第 <span id="currentPage">1</span> 页，共 <span id="totalPages">1</span> 页
                    </div>
                    <div class="pagination">
                        <button id="prevPage" class="btn-secondary" onclick="changePage(-1)" disabled>上一页</button>
                        <button id="nextPage" class="btn-secondary" onclick="changePage(1)">下一页</button>
                    </div>
                </div>
            </section>
        </div>
    </main>

    <script>
        // 主题切换功能
        document.addEventListener('DOMContentLoaded', function() {
            // 检查首选主题
            const savedTheme = localStorage.getItem('theme') || 'light';
            document.documentElement.setAttribute('data-theme', savedTheme);
            updateThemeIcon(savedTheme);
            
            // 主题切换事件
            document.getElementById('themeToggle').addEventListener('click', function() {
                const currentTheme = document.documentElement.getAttribute('data-theme');
                const newTheme = currentTheme === 'light' ? 'dark' : 'light';
                
                document.documentElement.setAttribute('data-theme', newTheme);
                localStorage.setItem('theme', newTheme);
                updateThemeIcon(newTheme);
            });
        });
        
        // 更新主题图标
        function updateThemeIcon(theme) {
            const iconContainer = document.getElementById('themeToggle');
            if (theme === 'dark') {
                iconContainer.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="5"></circle><path d="M12 1v2M12 21v2M4.2 4.2l1.4 1.4M18.4 18.4l1.4 1.4M1 12h2M21 12h2M4.2 19.8l1.4-1.4M18.4 5.6l1.4-1.4"></path></svg>`;
                iconContainer.title = "切换到明亮模式";
            } else {
                iconContainer.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"></path></svg>`;
                iconContainer.title = "切换到黑暗模式";
            }
        }
        
        // 全局变量
        let currentPage = 1;
        let totalPages = 1;
        let currentSortField = 'add_time';
        let currentSortOrder = 'desc';
        let keyFilter = '';
        let isMobile = window.innerWidth <= 768;

        // 初始化
        document.addEventListener('DOMContentLoaded', function() {
            loadKeys();
            fetchStats();
            setupResponsiveHandlers();
        });

        // 设置响应式处理
        function setupResponsiveHandlers() {
            // 处理窗口大小变化
            let resizeTimeout;
            window.addEventListener('resize', function() {
                clearTimeout(resizeTimeout);
                resizeTimeout = setTimeout(function() {
                    const newIsMobile = window.innerWidth <= 768;
                    if (newIsMobile !== isMobile) {
                        isMobile = newIsMobile;
                        // 重新加载表格以应用新的布局
                        loadKeys();
                    }
                }, 250);
            });
        }

        // 格式化密钥显示
        function formatKeyDisplay(key) {
            if (isMobile) {
                return `${key.substring(0, 6)}...${key.substring(key.length - 3)}`;
            } else {
                return `${key.substring(0, 8)}...${key.substring(key.length - 4)}`;
            }
        }

        // 格式化时间显示
        function formatDate(timestamp) {
            const date = new Date(timestamp * 1000);
            if (isMobile) {
                return `${date.getMonth()+1}/${date.getDate()} ${date.getHours()}:${String(date.getMinutes()).padStart(2, '0')}`;
            } else {
                return date.toLocaleString('zh-CN');
            }
        }

        // 显示消息
        function showMessage(text, type = 'success') {
            const messageEl = document.getElementById('message');
            messageEl.textContent = text;
            messageEl.className = type;
            messageEl.style.display = 'block';
            setTimeout(() => messageEl.style.display = 'none', 3000);
        }

        // 获取总体统计信息
        async function fetchStats() {
            try {
                const response = await fetch('/api/stats/overview');
                if (!response.ok) {
                    throw new Error('获取统计信息失败');
                }
                
                const data = await response.json();
                document.getElementById('totalKeysCount').textContent = data.key_count;
                document.getElementById('totalBalance').textContent = `¥${parseFloat(data.total_balance).toFixed(2)}`;
                document.getElementById('totalCallCount').textContent = data.total_calls || 0;
                document.getElementById('totalTokens').textContent = data.total_tokens || 0;
            } catch (error) {
                console.error('Error fetching stats:', error);
            }
        }

        // 加载密钥
        async function loadKeys() {
            try {
                const tbody = document.querySelector("#keysTable tbody");
                tbody.innerHTML = '<tr><td colspan="5" style="text-align: center;">加载中...</td></tr>';
                
                let url = `/api/keys?page=${currentPage}&sort_field=${currentSortField}&sort_order=${currentSortOrder}`;
                
                const response = await fetch(url);
                if (!response.ok) {
                    throw new Error(`获取密钥失败: ${response.status}`);
                }
                
                const data = await response.json();
                
                totalPages = Math.ceil(data.total / data.page_size);
                document.getElementById('currentPage').textContent = currentPage;
                document.getElementById('totalPages').textContent = totalPages;
                
                document.getElementById('prevPage').disabled = currentPage <= 1;
                document.getElementById('nextPage').disabled = currentPage >= totalPages;
                
                tbody.innerHTML = '';
                
                if (data.keys.length === 0) {
                    tbody.innerHTML = '<tr><td colspan="5" style="text-align: center;">没有找到密钥</td></tr>';
                    return;
                }
                
                const filteredKeys = keyFilter ? 
                    data.keys.filter(key => key.key.toLowerCase().includes(keyFilter.toLowerCase())) : 
                    data.keys;
                
                if (filteredKeys.length === 0) {
                    tbody.innerHTML = '<tr><td colspan="5" style="text-align: center;">没有找到匹配的密钥</td></tr>';
                    return;
                }
                
                // 更新表头排序指示器
                document.querySelectorAll('th').forEach(th => {
                    th.classList.remove('active');
                    const onclickAttr = th.getAttribute('onclick');
                    if (!onclickAttr) return;
                    
                    const matches = onclickAttr.match(/'([^']+)'/);
                    if (!matches) return;
                    
                    const field = matches[1];
                    if (field === currentSortField) {
                        th.classList.add('active');
                        const sortIndicator = currentSortOrder === 'asc' ? ' ↑' : ' ↓';
                        const baseText = th.textContent.replace(/ [↑↓]$/, '');
                        th.textContent = baseText + (field === 'key' ? '' : sortIndicator);
                    }
                });
                
                // 使用DocumentFragment减少DOM操作
                const fragment = document.createDocumentFragment();
                
                filteredKeys.forEach(key => {
                    const tr = document.createElement('tr');
                    tr.setAttribute('data-key', key.key);
                    
                    const maskedKey = formatKeyDisplay(key.key);
                    const formattedDate = formatDate(key.add_time);
                    
                    // 创建密钥列
                    const keyTd = document.createElement('td');
                    const keyDisplay = document.createElement('div');
                    keyDisplay.className = 'key-display';
                    
                    const keySpan = document.createElement('span');
                    keySpan.className = 'masked-key';
                    keySpan.title = "点击显示完整密钥";
                    keySpan.textContent = maskedKey;
                    keySpan.onclick = () => toggleKeyVisibility(keySpan, key.key);
                    
                    const copyBtn = document.createElement('button');
                    copyBtn.className = 'copy-btn';
                    copyBtn.title = "复制密钥";
                    copyBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                        <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
                        <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
                    </svg>`;
                    copyBtn.onclick = (event) => copyToClipboard(key.key, event);
                    
                    keyDisplay.appendChild(keySpan);
                    keyDisplay.appendChild(copyBtn);
                    keyTd.appendChild(keyDisplay);
                    
                    // 创建余额列
                    const balanceTd = document.createElement('td');
                    balanceTd.textContent = `¥${parseFloat(key.balance).toFixed(2)}`;
                    
                    // 创建使用次数列
                    const usageTd = document.createElement('td');
                    usageTd.textContent = key.usage_count;
                    
                    // 创建日期列
                    const dateTd = document.createElement('td');
                    dateTd.className = 'hide-on-mobile';
                    dateTd.textContent = formattedDate;
                    
                    // 创建操作列
                    const actionTd = document.createElement('td');
                    const actionDiv = document.createElement('div');
                    actionDiv.className = 'key-actions';
                    
                    const refreshBtn = document.createElement('button');
                    refreshBtn.className = 'action-btn refresh-btn';
                    refreshBtn.textContent = '刷新';
                    refreshBtn.onclick = () => refreshKey(key.key);
                    
                    actionDiv.appendChild(refreshBtn);
                    actionTd.appendChild(actionDiv);
                    
                    // 添加所有列到行
                    tr.appendChild(keyTd);
                    tr.appendChild(balanceTd);
                    tr.appendChild(usageTd);
                    tr.appendChild(dateTd);
                    tr.appendChild(actionTd);
                    
                    fragment.appendChild(tr);
                });
                
                tbody.appendChild(fragment);
                
            } catch (error) {
                showMessage(`加载密钥失败: ${error.message}`, "error");
            }
        }

        // 刷新单个密钥
        async function refreshKey(key) {
            try {
                const messageEl = document.getElementById("message");
                messageEl.textContent = "正在刷新，请稍候...";
                messageEl.className = "success";
                messageEl.style.display = 'block';
                
                const response = await fetch('/api/refresh_key', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify({ key: key })
                });
                
                if (!response.ok) {
                    throw new Error(`刷新失败: ${response.status}`);
                }
                
                const data = await response.json();
                messageEl.textContent = data.message;
                
                // 只更新这一行，而不是整个表格
                const keyRow = document.querySelector(`tr[data-key="${key}"]`);
                if (keyRow) {
                    // 获取最新的密钥信息
                    const keyResponse = await fetch(`/api/key_info?key=${key}`);
                    if (keyResponse.ok) {
                        const keyData = await keyResponse.json();
                        // 更新余额
                        const balanceCell = keyRow.querySelector('td:nth-child(2)');
                        if (balanceCell) {
                            balanceCell.textContent = `¥${parseFloat(keyData.balance).toFixed(2)}`;
                        }
                    }
                }
                
                // 更新统计信息
                fetchStats();
            } catch (error) {
                showMessage(`刷新密钥失败: ${error.message}`, "error");
            }
        }

        // 刷新所有密钥
        async function refreshAllKeys() {
            try {
                const messageEl = document.getElementById("message");
                messageEl.textContent = "正在刷新所有密钥，请稍候...";
                messageEl.className = "success";
                messageEl.style.display = 'block';
                
                const response = await fetch('/refresh', { method: 'POST' });
                const data = await response.json();
                messageEl.textContent = data.message;
                
                loadKeys();
                fetchStats();
            } catch (error) {
                showMessage('刷新失败：' + error.message, 'error');
            }
        }

        // 应用过滤器
        function applyFilters() {
            keyFilter = document.getElementById('keyFilter').value.trim().toLowerCase();
            currentPage = 1;
            loadKeys();
        }

        // 更改排序
        function changeSorting() {
            currentSortField = document.getElementById('sortField').value;
            currentSortOrder = document.getElementById('sortOrder').value;
            currentPage = 1;
            loadKeys();
        }

        // 点击表头排序
        function sortKeys(field) {
            if (currentSortField === field) {
                // 切换排序方向
                currentSortOrder = currentSortOrder === 'asc' ? 'desc' : 'asc';
            } else {
                currentSortField = field;
                currentSortOrder = 'desc';
            }
            
            // 更新排序下拉框
            document.getElementById('sortField').value = currentSortField;
            document.getElementById('sortOrder').value = currentSortOrder;
            
            currentPage = 1;
            loadKeys();
        }

        // 更改页码
        function changePage(delta) {
            const newPage = currentPage + delta;
            if (newPage >= 1 && newPage <= totalPages) {
                currentPage = newPage;
                loadKeys();
            }
        }

        // 切换密钥可见性
        function toggleKeyVisibility(element, fullKey) {
            const parent = element.parentElement;
            
            // 如果页面上有任何显示完整密钥的元素，先将其隐藏
            document.querySelectorAll('.full-key').forEach(el => {
                if (el !== element) {
                    const key = el.getAttribute('data-key');
                    const maskedKey = formatKeyDisplay(key);
                    el.innerHTML = maskedKey;
                    el.classList.remove('full-key');
                    el.classList.add('masked-key');
                    el.title = "点击显示完整密钥";
                }
            });
            
            if (element.classList.contains('masked-key')) {
                element.innerHTML = fullKey;
                element.classList.remove('masked-key');
                element.classList.add('full-key');
                element.setAttribute('data-key', fullKey);
                element.title = "点击隐藏密钥";
                
                // 设置自动隐藏定时器
                setTimeout(() => {
                    if (element.classList.contains('full-key')) {
                        const key = element.getAttribute('data-key');
                        const maskedKey = formatKeyDisplay(key);
                        element.innerHTML = maskedKey;
                        element.classList.remove('full-key');
                        element.classList.add('masked-key');
                        element.title = "点击显示完整密钥";
                    }
                }, 10000); // 10秒后自动隐藏
            } else {
                const maskedKey = formatKeyDisplay(fullKey);
                element.innerHTML = maskedKey;
                element.classList.remove('full-key');
                element.classList.add('masked-key');
                element.title = "点击显示完整密钥";
            }
        }

        // 复制功能
        function copyToClipboard(text, event) {
            event.stopPropagation(); // 阻止事件冒泡
            
            // 尝试使用现代 Clipboard API
            if (navigator.clipboard && window.isSecureContext) {
                navigator.clipboard.writeText(text)
                    .then(() => {
                        showMessage("密钥已复制到剪贴板", "success");
                    })
                    .catch((err) => {
                        console.error('复制失败:', err);
                        fallbackCopyToClipboard(text);
                    });
            } else {
                // 回退到旧方法
                fallbackCopyToClipboard(text);
            }
        }

        // 回退复制方法
        function fallbackCopyToClipboard(text) {
            // 创建一个临时的文本区域元素
            const textarea = document.createElement('textarea');
            textarea.value = text;
            textarea.style.position = 'fixed'; // 避免滚动到底部
            textarea.style.opacity = '0';
            document.body.appendChild(textarea);
            textarea.select();
            
            try {
                // 执行复制命令
                const successful = document.execCommand('copy');
                if (successful) {
                    showMessage("密钥已复制到剪贴板", "success");
                } else {
                    showMessage("复制失败，请手动复制", "error");
                }
            } catch (err) {
                showMessage("复制失败: " + err, "error");
                console.error('复制失败:', err);
            }
            
            // 移除临时元素
            document.body.removeChild(textarea);
        }
    </script>
</body>

</html>